#include "../config.h"

#include <glibmm/i18n.h>

#include "application.h"
#include "panel.h"

namespace gpyp {
namespace panel {

//========================
// Panel
void Panel::save_panel_size(RefPageElement conf) {
  switch(*position_) {
  case PANEL_POSITION_LEFT:
    conf->width() = paned_.get_position();
    break;
  case PANEL_POSITION_TOP:
    conf->height() = paned_.get_position();
    break;
  case PANEL_POSITION_RIGHT:
    conf->width() = paned_.get_width() - paned_.get_position();
    break;
  case PANEL_POSITION_BOTTOM:
    conf->height() = paned_.get_height() - paned_.get_position();
    break;
  default:
    log::err << "bug: Panel::save_panel_size" << log::endl;
    break;
  }
}
void Panel::load_panel_size(RefPageElement conf) {
  switch(*position_) {
  case PANEL_POSITION_LEFT:
    paned_.set_position(*conf->width());
    break;
  case PANEL_POSITION_TOP:
    paned_.set_position(*conf->height());
    break;
  case PANEL_POSITION_RIGHT:
    paned_.set_position(paned_.get_width() - *conf->width());
    break;
  case PANEL_POSITION_BOTTOM:
    paned_.set_position(paned_.get_height() - *conf->height());
    break;
  default:
    log::err << "bug: Panel::load_panel_size" << log::endl;
    break;
  }
}
void Panel::update_height() {
  Gtk::Widget *widget = get_nth_page(get_current_page());
  for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
    PageContext &pc = *iter;
    if (pc.page_ && &pc.page_->get_widget() == widget) {
      if (&pc != page_selected_) {
        if (page_selected_) save_panel_size(page_selected_->conf_);
        page_selected_ = &pc;
        load_panel_size(pc.conf_);
      }
      break;
    }
  }
}

void Panel::append_page(PageContext *pc) {
  pc->page_ = pc->slot_create_();
  if (pc->scrolled_window_) {
    Gtk::ScrolledWindow *sw = Gtk::manage(new Gtk::ScrolledWindow());
    sw->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
    sw->add(pc->page_->get_widget());
    sw->set_border_width(2);
    pc->page_->set_widget(*sw);
  }
  pc->page_->get_widget().show_all();
  //set_current_page(Gtk::Notebook::append_page(pc->page_->get_widget(), pc->label_, true));
  Gtk::Image *icon = new Gtk::Image(IconManager::load_icon(pc->icon_name_, IconManager::ICON_SIZE_16));
  set_current_page(Gtk::Notebook::append_page(pc->page_->get_widget(), *Gtk::manage(icon)));
#ifdef GTK_NOTEBOOK_TAB_REORDERABLE
  set_tab_reorderable(pc->page_->get_widget(), true);
#endif
}

bool Panel::init_idle() {
  for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
    if (*iter->conf_->enable()) append_page(&*iter);
    iter->conn_conf_enable_changed_ = iter->conf_->enable()->signal_changed()
      .connect(sigc::bind(sigc::mem_fun(*this, &Panel::page_enable_on_changed), &*iter));
  }
  for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
    if (*iter->conf_->enable() && *iter->conf_->position() >= 0) {
      reorder_child(iter->page_->get_widget(), *iter->conf_->position());
    }
  }
#ifdef GTK_NOTEBOOK_TAB_REORDERABLE
  conn_page_reordered_ = signal_page_reordered().connect(sigc::mem_fun(*this, &Panel::_on_page_reordered));
#endif
  initialized_ = true;

  if (is_realized()) Glib::signal_idle().connect(sigc::mem_fun(*this, &Panel::realize_idle));
  return false;
}

void Panel::on_presave() {
  if (page_selected_) save_panel_size(page_selected_->conf_);
  PageContext *p = get_active_page();
  if (p) conf_->active_page() = p->conf_->get_name();
}

bool Panel::realize_idle() {
  if (get_n_pages() > 0) {
    int p = get_current_page();
    for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
      if (iter->page_ && iter->conf_->get_name() == *conf_->active_page()) {
        int n = page_num(iter->page_->get_widget());
        if (n != p) {
          set_current_page(n);
        } else {
          update_height();
        }
        return false;
      }
    }
    update_height();
  } else {
    pages_.front().conf_->enable() = true;
  }
  return false;
}
void Panel::on_realize() {
  Gtk::Notebook::on_realize();
  if (initialized_) Glib::signal_idle().connect(sigc::mem_fun(*this, &Panel::realize_idle));
}
void Panel::on_unrealize() {
  PageContext *p = get_active_page();
  if (p) conf_->active_page() = p->conf_->get_name();
  page_selected_ = NULL;
  Gtk::Notebook::on_unrealize();
}
void Panel::on_switch_page(GtkNotebookPage *page, guint page_num) {
  Gtk::Notebook::on_switch_page(page, page_num);
  if (initialized_) update_height();
}
bool Panel::on_button_press_event(GdkEventButton *event) {
  if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
    menu_.popup(3, event->time);
    return true;
  }
  return Gtk::Notebook::on_button_press_event(event);
}
#ifdef GTK_NOTEBOOK_TAB_REORDERABLE
void Panel::_on_page_reordered(Gtk::Widget */*widget*/, guint /*position*/) {
  for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
    if (iter->page_) {
      gint pos = -1;
      gtk_container_child_get(GTK_CONTAINER(gobj()),
                              iter->page_->get_widget().gobj(),
                              "position", &pos,
                              NULL);
      iter->conf_->position() = pos;
    }
  }
}
#endif

void Panel::set_label_angle(Gtk::Widget *widget) {
  double angle = 0;
  switch(*conf_->tab_position()) {
  case Gtk::POS_LEFT:   angle = 90;  break;
  case Gtk::POS_RIGHT:  angle = 270; break;
  case Gtk::POS_TOP:    angle = 0;   break;
  case Gtk::POS_BOTTOM: angle = 0;   break;
  }

  Gtk::Label *label = dynamic_cast<Gtk::Label *>(widget);
  if (label) label->set_angle(angle);
}

void Panel::tab_position_on_changed() {
  set_tab_pos(*conf_->tab_position());

  const Gtk::Notebook::PageList &pages = Gtk::Notebook::pages();
  Gtk::Notebook::PageList::const_iterator iter;
  for(iter = pages.begin(); iter; ++iter) set_label_angle(iter->get_tab_label());
}

void Panel::page_enable_on_changed(PageContext *pc) {
  if (*pc->conf_->enable()) {
    if (!pc->page_) {
      append_page(pc);

      gint pos = -1;
      gtk_container_child_get(GTK_CONTAINER(gobj()),
                              pc->page_->get_widget().gobj(),
                              "position", &pos,
                              NULL);
      pc->conf_->position() = pos;
    }
  } else {
    if (pc->page_) {
      if (get_n_pages() == 1) {
        pc->conn_conf_enable_changed_.block();
        position_ = PANEL_POSITION_NONE;
        pc->conn_conf_enable_changed_.unblock();
      } else {
        remove_page(pc->page_->get_widget());
        delete pc->page_;
        pc->page_ = NULL;
        pc->conf_->position() = -1;
      }
    }
  }
}

Panel::PageContext *Panel::get_active_page() {
  Gtk::Widget *widget = get_nth_page(get_current_page());
  if (widget) {
    for(PageList::iterator iter = pages_.begin(); iter != pages_.end(); ++iter) {
      PageContext &pc = *iter;
      if (pc.page_ && &pc.page_->get_widget() == widget) return &pc;
    }
  }
  return NULL;
}

void Panel::install_page(RefPageElement       conf,
                         SlotCreatePanel      slot_create,
                         const Glib::ustring &icon_name,
                         const Glib::ustring &label,
                         bool                 scrolled_window) {
  PageContext *pc = new PageContext(conf, slot_create, icon_name, label, scrolled_window);
  if (initialized_) {
    page_enable_on_changed(pc);
    pc->conn_conf_enable_changed_ = conf->enable()->signal_changed()
      .connect(sigc::bind(sigc::mem_fun(*this, &Panel::page_enable_on_changed), pc));
  }
  pages_.push_back(pc);

  menu_add_remove_.append(*Gtk::manage(new CheckMenuItem(label, conf->enable())));
}

Panel::Panel(Application         &app,
             RefPanelElement      conf,
             RefAttributePanelPos position,
             Gtk::Paned          &paned) :
  app_          (app),
  conf_         (conf),
  position_     (position),
  paned_        (paned),
  initialized_  (false),
  page_selected_(NULL),
  mi_panel_left_  (_("_Left"),    position_, PANEL_POSITION_LEFT),
  mi_panel_right_ (_("_Right"),   position_, PANEL_POSITION_RIGHT),
  mi_panel_top_   (_("_Top"),     position_, PANEL_POSITION_TOP),
  mi_panel_bottom_(_("_Bottom"),  position_, PANEL_POSITION_BOTTOM),
  mi_panel_none_  (_("_Disable"), position_, PANEL_POSITION_NONE),
  mi_tab_left_    (_("_Left"),    conf_->tab_position(), Gtk::POS_LEFT),
  mi_tab_right_   (_("_Right"),   conf_->tab_position(), Gtk::POS_RIGHT),
  mi_tab_top_     (_("_Top"),     conf_->tab_position(), Gtk::POS_TOP),
  mi_tab_bottom_  (_("_Bottom"),  conf_->tab_position(), Gtk::POS_BOTTOM)
{
  GtkWidget *mi_add_remove = gtk_menu_item_new_with_mnemonic(_("_Add/Remove panel"));
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi_add_remove), GTK_WIDGET(menu_add_remove_.gobj()));
  gtk_menu_append(menu_.gobj(), mi_add_remove);

  GtkWidget *menu_panel = gtk_menu_new();
  gtk_menu_append(GTK_MENU(menu_panel), GTK_WIDGET(mi_panel_left_  .gobj()));
  gtk_menu_append(GTK_MENU(menu_panel), GTK_WIDGET(mi_panel_right_ .gobj()));
  gtk_menu_append(GTK_MENU(menu_panel), GTK_WIDGET(mi_panel_top_   .gobj()));
  gtk_menu_append(GTK_MENU(menu_panel), GTK_WIDGET(mi_panel_bottom_.gobj()));
  gtk_menu_append(GTK_MENU(menu_panel), GTK_WIDGET(mi_panel_none_  .gobj()));
  GtkWidget *mi_panel = gtk_menu_item_new_with_mnemonic(_("_Panel position"));
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi_panel), menu_panel);
  gtk_menu_append(menu_.gobj(), mi_panel);

  GtkWidget *menu_tab = gtk_menu_new();
  gtk_menu_append(GTK_MENU(menu_tab), GTK_WIDGET(mi_tab_left_  .gobj()));
  gtk_menu_append(GTK_MENU(menu_tab), GTK_WIDGET(mi_tab_right_ .gobj()));
  gtk_menu_append(GTK_MENU(menu_tab), GTK_WIDGET(mi_tab_top_   .gobj()));
  gtk_menu_append(GTK_MENU(menu_tab), GTK_WIDGET(mi_tab_bottom_.gobj()));
  GtkWidget *mi_tab = gtk_menu_item_new_with_mnemonic(_("_Tab position"));
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(mi_tab), menu_tab);
  gtk_menu_append(menu_.gobj(), mi_tab);

  menu_.show_all();

  tab_position_on_changed();
  conn_tab_position_changed_ = conf_->tab_position()->signal_changed()
    .connect(sigc::mem_fun(*this, &Panel::tab_position_on_changed));
  conn_conf_presave_ = conf_->signal_presave().connect(sigc::mem_fun(*this, &Panel::on_presave));

  show_all();

  Glib::signal_idle().connect(sigc::mem_fun(*this, &Panel::init_idle));
}
Panel::~Panel() {
#ifdef GTK_NOTEBOOK_TAB_REORDERABLE
  conn_page_reordered_.disconnect();
#endif
  conn_tab_position_changed_.disconnect();
  conn_conf_presave_.disconnect();
  initialized_ = false;
}

}/*panel*/
}/*gpyp*/
